#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h> 
#include <time.h>
#include <sys/time.h>
#include "keys.h"
#include "leds.h"
#include "public.h"

static struct key_info * info;
static unsigned char iflag = 0;
unsigned char wflag = 0;

/**
 * xy_key_open - open device
 * @none
 */
int xy_key_open(void)
{
    int dev = -1;

    dev = open(KEYS, O_RDONLY);
    if (dev <= 0) {
        ac_traces(MSG_LEVEL_ERROR, "open key device fail:%d\n", dev);
        return false;
    }  

    info = (struct key_info *) malloc (sizeof(struct key_info));
    if (!info) {
        ac_traces(MSG_LEVEL_ERROR, "malloc fail.");
        return false;
    }

    info->dev = dev;

    return true;
}

/**
 * xy_sync - sync
 * @none
 */
static int xy_sync(void)
{
    xy_popen("sync");

    return true;
}

/**
 * xy_reboot - reboot
 * @execute system command : reboot
 */
static void xy_reboot(union sigval v)
{
    if (execl("/sbin/reboot", "reboot", "executed by execl", NULL) < 0) 
        ac_traces(MSG_LEVEL_INFO, "error on execl");

    ac_traces(MSG_LEVEL_INFO, "system reboot");
    xy_led_poweroff();
}

/**
 * xy_halt - halt
 * @execute system command : halt
 */
static void xy_halt(union sigval v)
{
    if (execl("/sbin/halt", "halt", "executed by execl", NULL) < 0) 
        ac_traces(MSG_LEVEL_INFO, "error on execl");
  
    ac_traces(MSG_LEVEL_INFO, "system halt");
    xy_led_poweroff();
}

/**
 * xy_recorder_start - recorder start
 * @video and imu recorder start
 */
static void xy_recorder_start(void)
{
    xy_popen("/usr/local/bin/video_recorder &");
    sleep(1);
    xy_popen("/usr/local/bin/imu_recorder &");
    ac_traces(MSG_LEVEL_DEBUG, "recodder start");
    xy_trigger_mode_none(RED);
    xy_led_brightness(RED, LED_ON);
}

/**
 * xy_recorder_stop - recorder stop
 * @video and imu recorder stop
 */
static void xy_recorder_stop(void)
{
    xy_sync();
    sleep(1);
    xy_popen("Killall crond");
    xy_popen("killall video_recorder");
    xy_popen("killall imu_recorder");
    xy_sync();
    ac_traces(MSG_LEVEL_DEBUG, "recodder stop");
    xy_trigger_mode_none(RED);
    xy_led_brightness(RED, LED_OFF);
}

/**
 * xy_wifi_start - run wifi
 * @wifi start
 */
static void xy_wifi_start(void)
{
    system("/etc/wifi/run-wifi.sh &");
    //xy_popen("/etc/wifi/run-hostapd.sh &");
    ac_traces(MSG_LEVEL_DEBUG, "wifi start");
}

/**
 * xy_wifi_stop - stop wifi
 * @wifi stop
 */
static void xy_wifi_stop()
{
    xy_popen("/etc/wifi/stop-wifi.sh");
    ac_traces(MSG_LEVEL_DEBUG, "stop wifi");
}

/**
 * xy_set_keyevent - key event and timer init
 * @key : event and timer 
 */
static int xy_set_keyevent(struct keys * key)
{
    memset(&key->key_event, 0, sizeof (struct input_event));
    memset(&key->evp_reboot, 0, sizeof (struct sigevent));
    memset(&key->evp_power, 0, sizeof (struct sigevent));
    key->evp_reboot.sigev_value.sival_int = 103;
    key->evp_reboot.sigev_notify = SIGEV_THREAD;
    key->evp_reboot.sigev_notify_function = xy_reboot;
    key->evp_power.sigev_value.sival_int = 108;
    key->evp_power.sigev_notify = SIGEV_THREAD;
    key->evp_power.sigev_notify_function = xy_halt;
    key->it.it_interval.tv_sec = 1;
    key->it.it_interval.tv_nsec = 0;
    key->it.it_value.tv_sec = 5;
    key->it.it_value.tv_nsec = 0;

    return true;
}

/**
 * xy_key_scan_thread - key scan thread 
 * @none
 */
void * xy_key_scan_thread(void)
{
    int ret = -1;
    struct keys key;

    xy_set_keyevent(&key);
    while (true) {
        ret = lseek(info->dev, 0, SEEK_SET);
        ret = read(info->dev, &key.key_event, sizeof(key.key_event));

        if (ret) {
            /* pressed */
            if (key.key_event.type == EV_KEY && key.key_event.value == 1) {
                /* key1 recorder and halt */
                if (key.key_event.code == KEY1) {
                    ac_traces(MSG_LEVEL_DEBUG, "key1 pressed.\n");
                    if (timer_create(CLOCK_REALTIME, &key.evp_power, &key.timerid_power)
                        == -1) {
                        perror("fail to timer create for key1");
                        exit(-1);
                    }
                    if (timer_settime(key.timerid_power, 0, &key.it, NULL) == -1) {
                        perror("fail to timer settime for key1");
                        exit(-1);
                    }

                    /* short press */
                    if (!iflag) {
                        xy_recorder_start();
                        iflag = 1;
                    }
                    else {
                        xy_recorder_stop();
                        iflag = 0;
                    }
                }
                /* key2 wifi and reboot */
                else  if (key.key_event.code == KEY2) {
                    ac_traces(MSG_LEVEL_DEBUG, "key2 pressed.\n");
                    if (timer_create(CLOCK_REALTIME, &key.evp_reboot, &key.timerid_reboot)
                        == -1) {
                        perror("fail to timer create for key2");
                        exit(-1);
                    }
                    if (timer_settime(key.timerid_reboot, 0, &key.it, NULL) == -1) {
                        perror("fail to timer settime for key2");
                        exit(-1);
                    }

                    /* short press */
                    if (!wflag) {
                        xy_wifi_start();
                        wflag = 1;
                    }
                    else {
                        xy_wifi_stop();
                        wflag = 0;
                    }
                }                
            }
            /* released */
            else if (key.key_event.type == EV_KEY && key.key_event.value == 0) {
                if (key.key_event.code == KEY1) {
                    timer_delete(key.timerid_power);
                    ac_traces(MSG_LEVEL_DEBUG, "key1 released.\n");
                }
                else if (key.key_event.code == KEY2) {
                    timer_delete(key.timerid_reboot);
                    ac_traces(MSG_LEVEL_DEBUG, "key2 released.\n");
                }
            }
        }
    }
}

/**
 * xy_key_press_thread_run - key scan thread run
 * @none
 */
int xy_key_press_thread_run(void)
{
    pthread_attr_t attr;
    pthread_t key_id = 0;
    int ret = 0;
    void * ptr;

    pthread_attr_init(&attr);

    if (0 != (ret = pthread_create(&key_id, 
                                   &attr, 
                                   (void * (*)(void *))xy_key_scan_thread, NULL))) {
        ac_traces(MSG_LEVEL_ERROR, 
                  "create key scan thread fail. error=%d", ret);
        return false;
    }

    ac_traces(MSG_LEVEL_INFO, "key-scan thread create successfuly!");
    pthread_join(key_id, &ptr);

    return true;
}
